feat(watchlist): implement Plex watchlist GraphQL API support#3008
feat(watchlist): implement Plex watchlist GraphQL API support#3008xNul wants to merge 6 commits into
Conversation
Previous Plex Watchlist Sync was limited to those who logged into Seerr with their Plex accounts. GraphQL-based Plex Watchlist Sync expands sync to all who are friends with those who logged into Seerr and unrestricted/public Plex Watchlists. Oftentimes, just importing a Plex user is enough to allow Plex Watchlist Sync. BREAKING CHANGE: Addition of a new plexUuid column to the User table in the database.
GraphQL-based Plex Watchlist Sync requires usage of Plex UUIDs. Migration from older versions would result in a new User.plexUuid column, but filled with NULL values. Now, migration from older versions will automatically populate the User.plexUuid column where applicable.
Plex Watchlist Sync for a user may result in an access denied error. As a preventative measure and to minimize GQL requests, a check is now performed on the enabling of Plex Watchlist Sync for a user to validate access. Additionally, if access to a user's Plex Watchlist is denied in the course of normal operations, the user's Plex Watchlist Sync settings will be disabled.
📝 WalkthroughWalkthroughThis PR enables Plex watchlist fetching via GraphQL and Plex home user UUIDs, eliminating the requirement for individual user Plex tokens. New API methods retrieve home users and GraphQL-backed watchlists. Database migrations add ChangesPlex UUID-Based Watchlist via GraphQL
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
server/routes/auth.ts (1)
140-147:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPersist
plexUuidwhen updating an existing Plex-linked user.On Line 141+, the login refresh updates Plex fields but skips
plexUuid. Users upgraded from older data can stayplexUuid = null, which breaks UUID-based watchlist flows.Suggested patch
user.plexToken = body.authToken; user.plexId = account.id; + user.plexUuid = account.uuid ?? user.plexUuid; user.avatar = account.thumb; user.email = account.email; user.plexUsername = account.username; user.userType = UserType.PLEX;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/routes/auth.ts` around lines 140 - 147, The update block that refreshes Plex-linked user fields sets plexToken, plexId, avatar, email, plexUsername and userType but omits persisting plexUuid; set user.plexUuid = account.uuid (or the correct UUID property returned on the Plex account object) before calling userRepository.save(user) so legacy users get their plexUuid populated and saved. Ensure you reference the existing variables user, account and the save call (userRepository.save) in the same update flow.server/routes/discover.ts (1)
927-929:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPagination contract is currently broken for Plex watchlist.
Line 927 computes offset pagination, but Line 978 ignores it and always fetches by UUID without cursor input.
page > 1can therefore return incorrect/duplicate results.Also applies to: 977-983
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/routes/discover.ts` around lines 927 - 929, The pagination logic computes page and offset (page, offset, itemsPerPage) but the watchlist fetch path still ignores offset and always fetches by UUID, causing duplicates for page > 1; update the watchlist retrieval (the call around the code that fetches by UUID in this route handler) to accept pagination arguments (offset/limit or a cursor) and pass itemsPerPage and offset (or page) through to the data access method (e.g., modify getWatchlistItemsByUUID or replace it with a paginated method) so that results are limited and offset correctly for pages > 1; ensure the same fix is applied to the other occurrence referenced (the block around lines 977–983) so both branches honor the computed offset and itemsPerPage.server/routes/user/index.ts (1)
687-698:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUpdate
plexUuidfor already-existing users during Plex import.On Line 687+, existing users are refreshed with Plex profile data, but
plexUuidis never updated. This leaves legacy users without the UUID required by watchlist fetches.Suggested patch
if (user) { // Update the user's avatar with their Plex thumbnail, in case it changed user.avatar = account.thumb; user.email = account.email; user.plexUsername = account.username; + user.plexUuid = account.uuid ?? user.plexUuid; // In case the user was previously a local account if (user.userType === UserType.LOCAL) { user.userType = UserType.PLEX; user.plexId = parseInt(account.id); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/routes/user/index.ts` around lines 687 - 698, When updating an existing user in the if (user) block in server/routes/user/index.ts, also set the user's plexUuid from the Plex account payload before saving; e.g. assign user.plexUuid = account.uuid || account.id (or account.uuid if present) alongside the existing lines that set avatar/email/plexUsername and plexId, then call userRepository.save(user) as before so legacy users receive the required UUID for watchlist fetches.server/api/plextv.ts (2)
434-445:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't collapse every Plex failure into the access-denied sentinel.
The catch block always returns
endCursor: undefined, which is the same signal the callers use for an inaccessible watchlist. That means a transient timeout/5xx/schema issue can surface asWatchlistAccessDeniedinusersettings.ts, andwatchlistsync.tscan disable both sync toggles for a user even though access was never actually denied.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/api/plextv.ts` around lines 434 - 445, The catch block in server/api/plextv.ts currently maps every error to the access-denied sentinel (endCursor: undefined); change it so that you only return that sentinel when the error is an actual access-denied response (e.g., HTTP 401/403 or a Plex auth error), otherwise do not swallow the error—either rethrow the exception or return a non-sentinel response so callers can distinguish transient/server/schema failures; update the catch handling around logger.error to inspect e.status/e.code (or error message patterns) and only return the access-denied shape for true auth errors, leaving other errors to propagate.
391-394:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse
watchlistItem.idinstead of accessing a non-existent property.
WatchlistResponse.data.user.watchlist.nodesis declared as{ id: string }[], sowatchlistItem.ratingKeydoes not exist on this type. UsewatchlistItem.idin the log message.Suggested fix
- `Item with ratingKey ${watchlistItem.ratingKey} returned no metadata, skipping.`, + `Item with id ${watchlistItem.id} returned no metadata, skipping.`,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/api/plextv.ts` around lines 391 - 394, The log message in the block that checks if (!metadata) uses a non-existent property watchlistItem.ratingKey; change it to use watchlistItem.id instead so the logger.warn call references the correct property (e.g., `Item with id ${watchlistItem.id} returned no metadata, skipping.`) within the same `if (!metadata)` block where `watchlistItem` and `metadata` are checked (the logger.warn call).
🧹 Nitpick comments (1)
server/utils/seedTestDb.ts (1)
37-55: ⚡ Quick winUse distinct
plexUuidvalues per seeded user.Both seeded Plex users currently share the same UUID, which can mask UUID-routing/watchlist bugs in tests.
Suggested patch
- user.plexUuid = 'a63j9ad8'; + user.plexUuid = 'a63j9ad8-admin'; ... - otherUser.plexUuid = 'a63j9ad8'; + otherUser.plexUuid = 'a63j9ad8-friend';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/utils/seedTestDb.ts` around lines 37 - 55, Seeded Plex users share the same plexUuid which can hide routing/watchlist bugs; update the seeding in seedTestDb.ts so each user gets a unique plexUuid (e.g., change otherUser.plexUuid to a different value than user.plexUuid) and ensure any other seeded users also receive distinct plexUuid values; locate the assignments to user.plexUuid and otherUser.plexUuid in the file and give them different unique strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/api/plextv.ts`:
- Around line 306-317: getWatchlist currently only fetches the first page
(default first=20) and returns page-limited items and totalSize, so long lists
are truncated; update getWatchlist to follow pagination by looping while
pageInfo.hasNextPage is true, calling the same fetch logic with
pageInfo.endCursor/after to request subsequent pages, concatenating
PlexWatchlistItem results into a single items array, update endCursor to the
last page's endCursor, and set totalSize from the server-provided total (if
available) or the final items.length instead of per-page length; apply the same
pagination fix to the other similar blocks referenced (around lines 323-352 and
364-433) to ensure full list retrieval and correct totalSize reporting.
In `@server/lib/watchlistsync.ts`:
- Around line 45-58: The loop only updates users when account.email is truthy,
leaving managed Plex users (no email) with plexUuid null; remove the
account.email guard so every entry from mainPlexTv.getHomeUsers() (iterate
plexHomeUsersResponse.MediaContainer.User and use account.id) attempts to find
the matching user via
userRepository.createQueryBuilder('user').where('user.plexId = :id', { id:
account.id }).getOne(), and if found set user.plexUuid = account.uuid (or
account.uuid only when present) and await userRepository.save(user); this
ensures syncUserWatchlist() can find and sync managed users too.
In `@server/routes/user/usersettings.ts`:
- Around line 148-158: The current backfill logic for user.plexUuid incorrectly
requires account.email to be present before assigning account.uuid, causing
managed/home users without emails to never receive a UUID; update the loop
inside the plexTvApi.getHomeUsers() handling so that you match by
Number(account.id) === user.plexId regardless of account.email and set
user.plexUuid = account.uuid and call userRepository.save(user) when the id
matches (retain the existing break after save); remove the account.email
condition so UUIDs are populated for users without email addresses.
---
Outside diff comments:
In `@server/api/plextv.ts`:
- Around line 434-445: The catch block in server/api/plextv.ts currently maps
every error to the access-denied sentinel (endCursor: undefined); change it so
that you only return that sentinel when the error is an actual access-denied
response (e.g., HTTP 401/403 or a Plex auth error), otherwise do not swallow the
error—either rethrow the exception or return a non-sentinel response so callers
can distinguish transient/server/schema failures; update the catch handling
around logger.error to inspect e.status/e.code (or error message patterns) and
only return the access-denied shape for true auth errors, leaving other errors
to propagate.
- Around line 391-394: The log message in the block that checks if (!metadata)
uses a non-existent property watchlistItem.ratingKey; change it to use
watchlistItem.id instead so the logger.warn call references the correct property
(e.g., `Item with id ${watchlistItem.id} returned no metadata, skipping.`)
within the same `if (!metadata)` block where `watchlistItem` and `metadata` are
checked (the logger.warn call).
In `@server/routes/auth.ts`:
- Around line 140-147: The update block that refreshes Plex-linked user fields
sets plexToken, plexId, avatar, email, plexUsername and userType but omits
persisting plexUuid; set user.plexUuid = account.uuid (or the correct UUID
property returned on the Plex account object) before calling
userRepository.save(user) so legacy users get their plexUuid populated and
saved. Ensure you reference the existing variables user, account and the save
call (userRepository.save) in the same update flow.
In `@server/routes/discover.ts`:
- Around line 927-929: The pagination logic computes page and offset (page,
offset, itemsPerPage) but the watchlist fetch path still ignores offset and
always fetches by UUID, causing duplicates for page > 1; update the watchlist
retrieval (the call around the code that fetches by UUID in this route handler)
to accept pagination arguments (offset/limit or a cursor) and pass itemsPerPage
and offset (or page) through to the data access method (e.g., modify
getWatchlistItemsByUUID or replace it with a paginated method) so that results
are limited and offset correctly for pages > 1; ensure the same fix is applied
to the other occurrence referenced (the block around lines 977–983) so both
branches honor the computed offset and itemsPerPage.
In `@server/routes/user/index.ts`:
- Around line 687-698: When updating an existing user in the if (user) block in
server/routes/user/index.ts, also set the user's plexUuid from the Plex account
payload before saving; e.g. assign user.plexUuid = account.uuid || account.id
(or account.uuid if present) alongside the existing lines that set
avatar/email/plexUsername and plexId, then call userRepository.save(user) as
before so legacy users receive the required UUID for watchlist fetches.
---
Nitpick comments:
In `@server/utils/seedTestDb.ts`:
- Around line 37-55: Seeded Plex users share the same plexUuid which can hide
routing/watchlist bugs; update the seeding in seedTestDb.ts so each user gets a
unique plexUuid (e.g., change otherUser.plexUuid to a different value than
user.plexUuid) and ensure any other seeded users also receive distinct plexUuid
values; locate the assignments to user.plexUuid and otherUser.plexUuid in the
file and give them different unique strings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f24d628b-f1a6-4f03-aae7-8d31cfd5bb63
📒 Files selected for processing (12)
server/api/plextv.tsserver/constants/error.tsserver/entity/User.tsserver/lib/watchlistsync.tsserver/migration/postgres/1777262170937-AddPlexUuidToUser.tsserver/migration/sqlite/1777247406444-AddPlexUuidToUser.tsserver/routes/auth.tsserver/routes/discover.tsserver/routes/user/index.tsserver/routes/user/usersettings.tsserver/utils/seedTestDb.tssrc/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx
| public async getWatchlist( | ||
| uuid: string, | ||
| { | ||
| first = 20, | ||
| after = undefined, | ||
| }: { first?: number; after?: number | undefined } = {} | ||
| ): Promise<{ | ||
| first: number; | ||
| after: number | undefined; | ||
| endCursor: string | undefined; | ||
| totalSize: number; | ||
| items: PlexWatchlistItem[]; |
There was a problem hiding this comment.
This only processes the first watchlist page.
getWatchlist() fetches one page (first = 20) and never follows pageInfo.hasNextPage/endCursor. Every caller added in this PR uses the default path, so any Plex watchlist with more than 20 entries will be silently truncated during sync/import. totalSize is also derived from the current page length, so callers cannot detect the truncation from the return value.
Also applies to: 323-352, 364-433
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/api/plextv.ts` around lines 306 - 317, getWatchlist currently only
fetches the first page (default first=20) and returns page-limited items and
totalSize, so long lists are truncated; update getWatchlist to follow pagination
by looping while pageInfo.hasNextPage is true, calling the same fetch logic with
pageInfo.endCursor/after to request subsequent pages, concatenating
PlexWatchlistItem results into a single items array, update endCursor to the
last page's endCursor, and set totalSize from the server-provided total (if
available) or the final items.length instead of per-page length; apply the same
pagination fix to the other similar blocks referenced (around lines 323-352 and
364-433) to ensure full list retrieval and correct totalSize reporting.
There was a problem hiding this comment.
Known issue and to be done as stated in the PR description.
There was a problem hiding this comment.
@xNul, understood — thanks for the clarification! I can see the PR description already calls this out as an outstanding item with TODOs marking the relevant spots in the code. I'll defer to that tracking. Would you like me to open a follow-up GitHub issue to track the cursor-pagination implementation for getWatchlist() so it doesn't get lost after this PR merges?
(。•ᴗ•。)🐇
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
server/api/plextv.ts (1)
375-445:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't map generic failures to the access-denied sentinel.
Non-404 metadata errors are rethrown at Lines 382-383, and the outer catch then returns
{ endCursor: undefined }. The callers in this PR use that shape as “watchlist not accessible”, so a transient Plex/community failure or one bad metadata fetch can incorrectly block watchlist sync for a user who actually has access.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@server/api/plextv.ts` around lines 375 - 445, The outer catch currently swallows all errors and returns the "access-denied sentinel" (endCursor: undefined), which causes transient or unrelated failures to be treated as “no access”; change the final catch so it only maps explicit access-denied errors (e.g. e.response?.status === 401 || e.response?.status === 403) to the sentinel and otherwise rethrows the error (or preserve the cached endCursor via cachedWatchlist?.response.data?.user.watchlist.pageInfo.endCursor) so transient failures are not misclassified; update the catch block that currently logs via logger.error('Failed to retrieve watchlist items', ...) and returns { first, after, endCursor: undefined, ... } to perform the status check and rethrow for non-access errors.
🧹 Nitpick comments (1)
docs/using-seerr/plex/watchlist-auto-request.md (1)
63-65: 💤 Low valueConsider improving conciseness and clarity.
Two minor refinements for this warning callout:
- The title could be more concise: "Watchlist Inaccessible" instead of "Watchlist Not Accessible"
- The phrase "prerequisite
#1" could be clearer for users troubleshooting this error. Consider: "you have not satisfied any of the watchlist access options listed in the first prerequisite" or simply "your watchlist is not accessible to Seerr"📝 Proposed refinement
-:::warning Watchlist Not Accessible -If you receive the error "User's watchlist is not accessible." when saving your settings at the end of Step 2, you have not fulfilled prerequisite `#1`. +:::warning Watchlist Inaccessible +If you receive the error "User's watchlist is not accessible." when saving your settings at the end of Step 2, you have not satisfied any of the watchlist access options listed in the first prerequisite. :::🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/using-seerr/plex/watchlist-auto-request.md` around lines 63 - 65, Change the warning callout title from "Watchlist Not Accessible" to the more concise "Watchlist Inaccessible" and replace the vague phrase "you have not fulfilled prerequisite `#1`" with a clearer explanation such as "your watchlist is not accessible to Seerr" or "you have not satisfied any of the watchlist access options listed in the first prerequisite" so users immediately understand the cause and next steps; update the callout content in the watchlist warning block accordingly (look for the exact strings "Watchlist Not Accessible" and "prerequisite `#1`" to locate the text).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/api/plextv.ts`:
- Around line 306-315: The getWatchlist method's after cursor is incorrectly
typed as number; update the getWatchlist signature and its parameter
destructuring to use after: string | undefined (instead of number | undefined)
so it matches the GraphQL $after: String and pageInfo.endCursor string, ensure
any local uses that pass after into the GraphQL variables treat it as a string,
and update any callers/tests to stop casting cursors to number (or to pass
strings) so the internal API contract is consistent; reference: getWatchlist.
---
Outside diff comments:
In `@server/api/plextv.ts`:
- Around line 375-445: The outer catch currently swallows all errors and returns
the "access-denied sentinel" (endCursor: undefined), which causes transient or
unrelated failures to be treated as “no access”; change the final catch so it
only maps explicit access-denied errors (e.g. e.response?.status === 401 ||
e.response?.status === 403) to the sentinel and otherwise rethrows the error (or
preserve the cached endCursor via
cachedWatchlist?.response.data?.user.watchlist.pageInfo.endCursor) so transient
failures are not misclassified; update the catch block that currently logs via
logger.error('Failed to retrieve watchlist items', ...) and returns { first,
after, endCursor: undefined, ... } to perform the status check and rethrow for
non-access errors.
---
Nitpick comments:
In `@docs/using-seerr/plex/watchlist-auto-request.md`:
- Around line 63-65: Change the warning callout title from "Watchlist Not
Accessible" to the more concise "Watchlist Inaccessible" and replace the vague
phrase "you have not fulfilled prerequisite `#1`" with a clearer explanation such
as "your watchlist is not accessible to Seerr" or "you have not satisfied any of
the watchlist access options listed in the first prerequisite" so users
immediately understand the cause and next steps; update the callout content in
the watchlist warning block accordingly (look for the exact strings "Watchlist
Not Accessible" and "prerequisite `#1`" to locate the text).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7cc59099-6791-4597-80ae-dca20fbedb77
📒 Files selected for processing (8)
docs/using-seerr/plex/watchlist-auto-request.mdserver/api/plextv.tsserver/lib/watchlistsync.tsserver/routes/auth.tsserver/routes/user/index.tsserver/routes/user/usersettings.tsserver/utils/seedTestDb.tssrc/i18n/locale/en.json
✅ Files skipped from review due to trivial changes (1)
- src/i18n/locale/en.json
🚧 Files skipped from review as they are similar to previous changes (3)
- server/routes/user/usersettings.ts
- server/routes/user/index.ts
- server/lib/watchlistsync.ts
|
For those 8 outside diff range + nitpick comments:
Which just leaves pagination and maybe #4. |
Description
This PR builds off of #1426 and aims to close #1378.
Currently, Seerr's Plex watchlist sync functionality requires each Plex user's individual user token. This is a burden on the user because it means they have to get the login credentials for every Plex user's account or have the user access Seerr and login themselves. For situations where obtaining a user's token isn't possible or there is no desire to give access to Seerr's web interface, Seerr hasn't been able to do a watchlist sync.
However, this is possible to do with Plex's GraphQL API. The only requirement to access a user's watchlist via the GraphQL API is that the user's watchlist is accessible to the user token which is making the API call. For example, if a user makes their watchlist public, it can be synced. If a user is friends with the user token which is making the API call, it can be synced.
Since the owner of a Seerr instance is the owner of the Plex media server, the Plex media server owner can add their users as friends (an easier task, if they aren't already friends) and have access to all of the watchlists of the media server. This means, there is no need to have each Plex user login to Seerr in order to provide Plex watchlist sync functionality.
Originally, PR #1426 was closed by the author with the expectation Plex was about to provide a public API which would officially solve this issue. It has been over a year now and as far as I can tell, no such API has been released so I have brought the PR back.
Progress Checklist
getWatchlistfrom API tokennullgetWatchlisterror handling?Important Changes
plexUuidcolumn has been added to theUserentity/table./api/home/usersis used to provide all the Plex UUIDs and replaces the/api/usersPlex API call during/import-from-plexPlex user import.The Pagination Issue
Pagination in Seerr is built around offsets, but the GraphQL watchlist API uses cursors. More info here. We need a way to bridge the gap and I'm not sure which way to go. I have marked the respective areas where pagination needs to be fixed with
TODOcomments.The page is set via the
pagequery parameterseerr/server/routes/user/index.ts
Line 951 in dfde4d3
which can be set 1-n at any point in time. With offset-based pagination, that's a simple operation that only returns
page_sizeresults for a givenpage, but cursor-based pagination would require consumingpage_size*pageresults to find the results for a givenpage. Page caching should help here though.Edit: The cursor for each watchlist item is simply when the item was added in unix epoch time encoded in base64. We can do a lot with this knowledge.
Edit 2: I have reverse engineered the GraphQL fields for
GetWatchlistHub. There may still be more, but I don't think there are any left that are related to pagination.Click to expand GetWatchlistHub example query
How Has This Been Tested?
pnpm testScreenshots / Logs (if applicable)
Example attempt to enable plex watchlist sync without access to it
Checklist:
pnpm buildpnpm i18n:extractAI Disclosure: The equivalent of Googling. AI was not used to write any of this code.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation